#light
namespace FSharp.WebTools.ClientControls

open System
open System.Web
open System.Web.UI
open System.Web.UI.WebControls

open Microsoft.FSharp.Quotations.Typed

open FSharp.WebTools
open FSharp.WebTools.Core
open FSharp.WebTools.ClientLibrary

module ClientCtl = begin
  let clientDummy () = client { return failwith "!" }
end
open ClientCtl

(*-----------------------------------------------------------------------------------------------*)

[<NativeClientSide("Dom.Label")>]
type Label() = class
  inherit System.Web.UI.WebControls.Label() as base
  interface INamingContainer
  interface IClientControl
  
(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - renamed from 'Visible' *)
  member this.ClientVisible 
    with get() = base.Visible
    and set(v:bool) = base.Visible <- v

  member this.Position 
    with get() = (failwith "!":Position);
    and set(v:Position) = (failwith "!":unit);

  member this.Size 
    with set(v:Size) = (failwith "!":unit);
    
  member this.AppendChild (el : IElement) =
    (failwith "!" : unit)

  member this.SetupDragDrop (el : IElement) = 
    (failwith "!":unit);

(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - renamed from 'Text' *)
  member this.ClientText
    with get() = 
      makeDuplex 
        (let n = base.Text in server { return n })
        (client { return "nada!" })
    and set(v:string) = 
      makeDuplex 
        (server { do! <@! ( _ : WebControls.Label).Text <- (_ : string) !@> (lift (this :> WebControls.Label)) (lift v) })
        (client { do  Window.Alert("todo!"); })
end

(*-----------------------------------------------------------------------------------------------*)

[<NativeClientSide("Dom.Element")>]
type Element() = class
  inherit System.Web.UI.WebControls.Panel() as base
  interface INamingContainer
  interface IClientControl

(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - renamed from 'Visible' *)
  member this.ClientVisible 
    with get() = base.Visible
    and set(v:bool) = base.Visible <- v

  member this.Position 
    with get() = (failwith "!":Position);
    and set(v:Position) = (failwith "!":unit);

  member this.Size 
    with set(v:Size) = (failwith "!":unit);
    
  member this.AppendChild (el : IElement) =
    (failwith "!" : unit)

  member this.SetupDragDrop (el : IElement) = 
    (failwith "!":unit);

  member this.InnerHtml 
    with get() = (failwith "!":string)
    and set(v:string) = (failwith "!":unit)

  member this.InnerText
    with get() = (failwith "!":string)
    and set(v:string) = (failwith "!":unit)
end

(*-----------------------------------------------------------------------------------------------*)

[<NativeClientSide("Dom.TextBox")>]
type TextBox() = class
  inherit System.Web.UI.WebControls.TextBox() as base
  interface INamingContainer
  interface IClientControl

  member this.Text
    with get() : string = base.Text
    and  set(v:string) : unit = base.Text <- v
    
  member this.ClientTextChanged
    with get() = (failwith "!": ClientEvent)

  member this.ClientKeyUp
    with get() = (failwith "!": ClientEvent)

  member this.ClientKeyDown
    with get() = (failwith "!": ClientEvent)

  member this.ClientKeyPress
    with get() = (failwith "!": ClientEvent)
      
(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - renamed from 'Visible' *)
  member this.ClientVisible 
    with get() = base.Visible
    and set(v:bool) = base.Visible <- v

(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - added aside from 'Text' *)
  member this.ClientText
    with get() : string = base.Text
    and  set(v:string) : unit = base.Text <- v

  member this.Position 
    with get() = (failwith "!":Position);
    and set(v:Position) = (failwith "!":unit);

  member this.Size 
    with set(v:Size) = (failwith "!":unit);
    
  member this.AppendChild (el : IElement) =
    (failwith "!" : unit)

  member this.SetupDragDrop (el : IElement) = 
    (failwith "!":unit);

end

(*-----------------------------------------------------------------------------------------------*)

[<NativeClientSide("Dom.RadioButton")>]
type RadioButton() = class
  inherit System.Web.UI.WebControls.RadioButton() as base
  interface INamingContainer
  interface IClientControl

  member this.Checked
    with get() = base.Checked
    and set(v:bool) = base.Checked <- v

  member this.ClientCheckedChanged 
    with get() = (failwith "!": ClientEvent)

(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - renamed from 'Visible' *)
  member this.ClientVisible 
    with get() = base.Visible
    and set(v:bool) = base.Visible <- v

  member this.Position 
    with get() = (failwith "!":Position);
    and set(v:Position) = (failwith "!":unit);

  member this.Size 
    with set(v:Size) = (failwith "!":unit);
    
  member this.AppendChild (el : IElement) =
    (failwith "!" : unit)

  member this.SetupDragDrop (el : IElement) = 
    (failwith "!":unit);

end

(*-----------------------------------------------------------------------------------------------*)

[<NativeClientSide("Dom.Button")>]
type Button() = class
  inherit System.Web.UI.WebControls.Button() as base
  interface INamingContainer
  interface IClientControl

  member this.Text
    with get() = base.Text
    and set(v:string) = base.Text <- v

  member this.ClientClick 
    with get() = (failwith "!": ClientEvent)

(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - renamed from 'Visible' *)
  member this.ClientVisible 
    with get() = base.Visible
    and set(v:bool) = base.Visible <- v

  member this.Position 
    with get() = (failwith "!":Position);
    and set(v:Position) = (failwith "!":unit);

  member this.Size 
    with set(v:Size) = (failwith "!":unit);
    
  member this.AppendChild (el : IElement) =
    (failwith "!" : unit)

  member this.SetupDragDrop (el : IElement) = 
    (failwith "!":unit);

end

(*-----------------------------------------------------------------------------------------------*)

[<NativeClientSide("Dom.LinkButton")>]
type LinkButton() = class
  inherit System.Web.UI.WebControls.LinkButton() as base
  interface INamingContainer
  interface IClientControl

  member this.Text
    with get() = base.Text
    and set(v:string) = base.Text <- v

  member this.ClientClick 
    with get() = (failwith "!": ClientEvent)

(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - renamed from 'Visible' *)
  member this.ClientVisible 
    with get() = base.Visible
    and set(v:bool) = base.Visible <- v

  member this.Position 
    with get() = (failwith "!":Position);
    and set(v:Position) = (failwith "!":unit);

  member this.Size 
    with set(v:Size) = (failwith "!":unit);
    
  member this.AppendChild (el : IElement) =
    (failwith "!" : unit)

  member this.SetupDragDrop (el : IElement) = 
    (failwith "!":unit);

  member this.Enabled
    with get() = 
      makeDuplex
        (server { return (this :> WebControls.LinkButton).Enabled })
        (clientDummy ())
    and set(v:bool) = 
      makeDuplex
        (server { do! <@! (_ : WebControls.LinkButton).Enabled <- (_) !@> (lift (this :> WebControls.LinkButton)) (lift v) })
        (clientDummy ())

  override this.Render(wr:HtmlTextWriter) =   
    wr.Write
      (sprintf "<a id=\"%s\" href=\"%s\"%s>%s</a>"
        this.ClientID (this.Page.GetPostBackClientHyperlink(this,""))
        (if (base.Enabled) then "" else "disabled=\"disabled\"") this.Text)
   
end

(*-----------------------------------------------------------------------------------------------*)

[<NativeClientSide("Dom.HyperLink")>]
type HyperLink() = class
  inherit System.Web.UI.WebControls.HyperLink() as base
  interface INamingContainer
  interface IClientControl

  member this.Text
    with get() = base.Text
    and set(v:string) = base.Text <- v

  member this.ClientClick 
    with get() = (failwith "!": ClientEvent)

(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - renamed from 'Visible' *)
  member this.ClientVisible 
    with get() = base.Visible
    and set(v:bool) = base.Visible <- v

  member this.Position 
    with get() = (failwith "!":Position);
    and set(v:Position) = (failwith "!":unit);

  member this.Size 
    with set(v:Size) = (failwith "!":unit);
    
  member this.AppendChild (el : IElement) =
    (failwith "!" : unit)

  member this.SetupDragDrop (el : IElement) = 
    (failwith "!":unit);

  member this.NavigateUrl
    with get() = 
      makeDuplex
        (server { return (this :> WebControls.HyperLink).NavigateUrl })
        (clientDummy ())
    and set(v:string) = 
      makeDuplex
        (server { do! <@! (_ : WebControls.HyperLink).NavigateUrl <- (_) !@> (lift (this :> WebControls.HyperLink)) (lift v) })
        (clientDummy ())
        
  member this.Enabled
    with get() = 
      makeDuplex
        (server { return (this :> WebControls.HyperLink).Enabled })
        (clientDummy ())
    and set(v:bool) = 
      makeDuplex
        (server { do! <@! (_ : WebControls.HyperLink).Enabled <- (_) !@> (lift (this :> WebControls.HyperLink)) (lift v) })
        (clientDummy ())

  override this.Render(wr:HtmlTextWriter) =   
    wr.Write
      (sprintf "<a id=\"%s\" href=\"%s\"%s>%s</a>"
        this.ClientID (this :> WebControls.HyperLink).NavigateUrl
        (if (base.Enabled) then "" else "disabled=\"disabled\"") this.Text)
        
end

(*-----------------------------------------------------------------------------------------------*)

[<NativeClientSide("Dom.Image")>]
type Image() = class
  inherit System.Web.UI.WebControls.Image() as base

  let mutable visible = true

  interface INamingContainer
  interface IClientControl

  member this.ClientClick 
    with get() = (failwith "!": ClientEvent)

(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3 
    - renamed from just 'Visible' *)
  member this.ClientVisible
    with get() = 
      makeDuplex
        (server { return visible })
        (clientDummy ())
    and set(v:bool) = 
      makeDuplex
        (server { do visible <- v })
        (clientDummy ())

  member this.Position 
    with get() = (failwith "!":Position);
    and set(v:Position) = (failwith "!":unit);

  member this.Size 
    with set(v:Size) = (failwith "!":unit);
    
  member this.AppendChild (el : IElement) =
    (failwith "!" : unit)

  member this.SetupDragDrop (el : IElement) = 
    (failwith "!":unit);

  member this.ImageUrl
    with get() = base.ImageUrl
    and set(v:string) = base.ImageUrl <- v

(* WORKAROUND: for the 'convMethodRef' bug in F# 1.9.3          
    - added aside from 'ImageUrl' *)

  member this.ClientImageUrl
    with get() = base.ImageUrl
    and set(v:string) = base.ImageUrl <- v
    
  override this.Render(wr:HtmlTextWriter) =   
    wr.Write
      (sprintf "<img id=\"%s\" src=\"%s\"%s />"
        this.ClientID this.ImageUrl
        (if (visible) then "" else " style=\"visibility:hidden;\""))
    
end

(*-------------------------------------------------------------------------------------------------
    NOT IMPLEMENTED IN JAVASCRIPT

[<MixedSide>]
type LinkButton() = class
  inherit System.Web.UI.WebControls.LinkButton() as base
  interface INamingContainer
  interface IClientControl

  // [members shared in every control]
  
  member this.Base =
    (this :> WebControls.LinkButton)
    
  [<ReflectedDefinition>]
  member this.AppendChild (el : IElement) =
    client { let! h = this.HtmlElement in do h.AppendChild(el) }
        
  [<ReflectedDefinition>]
  member this.SetupDragDrop (el : IElement) = 
    client { let! h = this.HtmlElement in do h.SetupDragDrop(el) }

  [<ReflectedDefinition>]
  member this.Position 
    with get() = client { let! h = this.HtmlElement in -> h.Position }
    and set(v:Position) = client { let! h = this.HtmlElement in do h.Position <- v }

  [<ReflectedDefinition>]
  member this.Size 
    (*with get() = client { let! h = this.HtmlElement in -> h.Size }*)
    with set(v:Size) = client { let! h = this.HtmlElement in do h.Size <- v }

  [<ReflectedDefinition>]
  member this.InnerHtml 
    with get() = client { let! h = this.HtmlElement in -> h.InnerHtml }
    and set(v) = client { let! h = this.HtmlElement in do h.InnerHtml <- v }
          
  [<ReflectedDefinition>]
  member this.InnerText 
    with get() = client { let! h = this.HtmlElement in -> h.InnerText }
    and set(v) = client { let! h = this.HtmlElement in do h.InnerText <- v }    

  [<ReflectedDefinition>]
  member this.ClientClick 
    with get() = client { let! h = this.HtmlElement in -> h.ClientClick }

  [<ReflectedDefinition>]
  member this.Visible 
    with get() = 
      makeDuplex 
        (server { -> this.Base.Visible })
        (client { let! h = this.HtmlElement in -> h.Visible })
    and set(v) = 
      makeDuplex
        (server { do! <@! (_ : WebControls.LinkButton).Visible <- (_) !@> (lift this.Base) (lift v) })
        (client { let! h = this.HtmlElement in do h.Visible <- v })
  
  [<ReflectedDefinition>]
  member this.GetChild (s:string) =
    client { do Window.Alert("GetChild not supported!") } 

  // [/members shared in every control]

  [<ReflectedDefinition>]
  member this.Enabled
    with get() =  // can't use base here due to the quoting
      makeDuplex 
        (server { -> this.Base.Enabled })
        (client { -> ClientCore.GetMember(this, "enabled"); })
    and set(v) = 
      makeDuplex 
        (server { do! <@! (_ : WebControls.LinkButton).Enabled <- (_) !@> (lift this.Base) (lift v) })
        (client { do  ClientCore.SetMember(this, "enabled", v); })
      
end

(*-----------------------------------------------------------------------------------------------*)

[<PartialClientClass(NativeBase="Dom.Element")>]
type HyperLink() = class
  inherit System.Web.UI.WebControls.HyperLink() as base
  interface INamingContainer
  interface IClientControl

  // [members shared in every control]
  
  [<ReflectedDefinition>]
  member this.Base =
    (this :> WebControls.HyperLink)
    
  [<ReflectedDefinition>]
  member this.AppendChild (el : IElement) =
    client { let! h = this.HtmlElement in do h.AppendChild(el) }
        
  [<ReflectedDefinition>]
  member this.SetupDragDrop (el : IElement) = 
    client { let! h = this.HtmlElement in do h.SetupDragDrop(el) }

  [<ReflectedDefinition>]
  member this.Position 
    with get() = client { let! h = this.HtmlElement in -> h.Position }
    and set(v:Position) = client { let! h = this.HtmlElement in do h.Position <- v }

  [<ReflectedDefinition>]
  member this.Size 
    (*with get() = client { let! h = this.HtmlElement in -> h.Size }*)
    with set(v:Size) = client { let! h = this.HtmlElement in do h.Size <- v }

  [<ReflectedDefinition>]
  member this.InnerHtml 
    with get() = client { let! h = this.HtmlElement in -> h.InnerHtml }
    and set(v) = client { let! h = this.HtmlElement in do h.InnerHtml <- v }
          
  [<ReflectedDefinition>]
  member this.InnerText 
    with get() = client { let! h = this.HtmlElement in -> h.InnerText }
    and set(v) = client { let! h = this.HtmlElement in do h.InnerText <- v }    

  [<ReflectedDefinition>]
  member this.ClientClick 
    with get() = client { let! h = this.HtmlElement in -> h.ClientClick }

  [<ReflectedDefinition>]
  member this.Visible 
    with get() = 
      makeDuplex 
        (server { -> this.Base.Visible })
        (client { let! h = this.HtmlElement in -> h.Visible })
    and set(v) = 
      makeDuplex
        (server { do! <@! (_ : WebControls.HyperLink).Visible <- (_) !@> (lift this.Base) (lift v) })
        (client { let! h = this.HtmlElement in do h.Visible <- v })
  
  [<ReflectedDefinition>]
  member this.GetChild (s:string) =
    client { do Window.Alert("GetChild not supported!") } 

  // [/members shared in every control]

  [<ReflectedDefinition>]
  member this.NavigateUrl
    with get() =  // can't use base here due to the quoting
      makeDuplex 
        (server { -> this.Base.NavigateUrl })
        (client { -> ClientCore.GetMember(this, "href"); })
    and set(v) = 
      makeDuplex 
        (server { do! <@! (_ : WebControls.HyperLink).NavigateUrl <- (_) !@> (lift this.Base) (lift v) })
        (client { do  ClientCore.SetMember(this, "href", v); })
      
end

(*-----------------------------------------------------------------------------------------------*)

[<PartialClientClass(NativeBase="Dom.Element")>]
type MImage() = class
  inherit System.Web.UI.WebControls.Image() as base
  interface INamingContainer
  interface IClientControl

  // [members shared in every control]
  
  [<ReflectedDefinition>]
  member this.Base =
    (this :> WebControls.Image)
    
  [<ReflectedDefinition>]
  member this.AppendChild (el : IElement) =
    client { let! h = this.HtmlElement in do h.AppendChild(el) }
        
  [<ReflectedDefinition>]
  member this.SetupDragDrop (el : IElement) = 
    client { let! h = this.HtmlElement in do h.SetupDragDrop(el) }

  [<ReflectedDefinition>]
  member this.Position 
    with get() = client { let! h = this.HtmlElement in -> h.Position }
    and set(v:Position) = client { let! h = this.HtmlElement in do h.Position <- v }

  [<ReflectedDefinition>]
  member this.Size 
    (*with get() = client { let! h = this.HtmlElement in -> h.Size }*)
    with set(v:Size) = client { let! h = this.HtmlElement in do h.Size <- v }

  [<ReflectedDefinition>]
  member this.InnerHtml 
    with get() = client { let! h = this.HtmlElement in -> h.InnerHtml }
    and set(v) = client { let! h = this.HtmlElement in do h.InnerHtml <- v }
          
  [<ReflectedDefinition>]
  member this.InnerText 
    with get() = client { let! h = this.HtmlElement in -> h.InnerText }
    and set(v) = client { let! h = this.HtmlElement in do h.InnerText <- v }    

  [<ReflectedDefinition>]
  member this.ClientClick 
    with get() = client { let! h = this.HtmlElement in -> h.ClientClick }

  [<ReflectedDefinition>]
  member this.Visible 
    with get() = 
      makeDuplex 
        (server { -> this.Base.Visible })
        (client { let! h = this.HtmlElement in -> h.Visible })
    and set(v) = 
      makeDuplex
        (server { do! <@! (_ : WebControls.Image).Visible <- (_) !@> (lift this.Base) (lift v) })
        (client { let! h = this.HtmlElement in do h.Visible <- v })
  
  [<ReflectedDefinition>]
  member this.GetChild (s:string) =
    client { do Window.Alert("GetChild not supported!") } 

  // [/members shared in every control]

  [<ReflectedDefinition>]
  member this.ImageUrl
    with get() =  // can't use base here due to the quoting
      makeDuplex 
        (server { -> this.Base.ImageUrl })
        (client { -> ClientCore.GetMember(this, "src"); })
    and set(v) = 
      makeDuplex 
        (server { do! <@! (_ : WebControls.Image).ImageUrl <- (_) !@> (lift this.Base) (lift v) })
        (client { do  ClientCore.SetMember(this, "src", v); })
      
end

-----------------------------------------------------------------------------------------------*)
